home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Workspace / Briefcase / Source / Help.m < prev    next >
Text File  |  1995-06-12  |  7KB  |  224 lines

  1. /* 
  2.  * Help.m, a help object to manage and display RTF help files.
  3.  * The help object owns its own nib section "Help.nib" which has a
  4.  * Help panel - with an NXBrowser to display the help topics, and
  5.  * a scrolling text view to display the help files.  The help files are
  6.  * all stored as RTF text files in a directory called Help within the
  7.  * app wrapper.  At init time, the Help object loads the browser with 
  8.  * names of all the files found in the Help directory.  When a name is
  9.  * chosen from the browser, the help object opens a stream on that file
  10.  * and read the rich text into the text object. The help object also
  11.  * responds to request for context-sensitive help, by trying to find an
  12.  * appropriate help file for the view that was moused down in.
  13.  * This object is a useful addition to any program, because all users
  14.  * appreciate help!
  15.  *
  16.  * Author: Julie Zelenski, NeXT Developer Support
  17.  * You may freely copy, distribute and reuse the code in this example.  
  18.  * NeXT disclaims any warranty of any kind, expressed or implied, as to 
  19.  * its fitness for any particular use.
  20.  */
  21.  
  22. /* Modified starting 9/21/91 by Subrata K. Sircar */
  23. /* Mostly I've removed functionality. */
  24.  
  25. #import "Help.h"
  26. #import <appkit/appkit.h>
  27. #import <sys/dir.h> //for getdirentries()
  28.  
  29. #define    GENERAL_HELP_FILE    LocalString("General Help.rtf")
  30.  
  31. @implementation Help:Object
  32.  
  33. - init 
  34. {
  35.     LocalHelp(helpDirectory,LocalString("Help"));
  36.     sprintf(noHelpFile,"%s/%s",helpDirectory,GENERAL_HELP_FILE);
  37.     return self;
  38. }
  39.  
  40. - setHelpBrowser:anObject;
  41. /* Sets the helpBrowser outlet, and calls on the browser to load up.
  42.  */
  43. {
  44.     helpBrowser = anObject;
  45.     [helpBrowser setDelegate:self];
  46.     [helpBrowser loadColumnZero];
  47.     return self;
  48. }
  49.  
  50. /* TARGET/ACTION METHODS */
  51.  
  52. - generalHelp:sender;
  53. /* This is the target/action method for the "Help" menu item.  This method 
  54.  * will show the "general help" file.
  55.  */
  56. {
  57.     [self showHelpFile:GENERAL_HELP_FILE];
  58.     return self;
  59. }
  60.  
  61. - browserHit:sender
  62. /* This is the target/action method from the help topics browser.  When
  63.  * a help topic is selected, this method will show the help file for that
  64.  * topic.
  65.  */
  66. {   
  67.     [self showHelpFile:[[[sender matrixInColumn:0] selectedCell] stringValue]];
  68.     return self;
  69. }
  70.  
  71.  
  72. - print:sender;
  73. /* This method is called by the Print menu cell in the main menu.  It will 
  74.  * print the current help file.
  75.  */
  76. {
  77.     [[helpScrollView docView] printPSCode:sender];
  78.     return self;
  79. }
  80.  
  81. - showHelpFile:(const char *)filename;
  82. /* Tries to open a stream for the specified file in the Help 
  83.  * directory so the text object can readRichText.  Also selects the
  84.  * filename in the browser of help topics.  If the filename doesn't exist,
  85.  * it will select and display the "no help" file.  It also brings the
  86.  * help panel to the front.
  87.  */
  88. {
  89.    NXStream *stream;
  90.    char helpFile[MAXPATHLEN+1];
  91.    static NXPoint origin = {0.0,0.0};
  92.  
  93.     if (![self browser:helpBrowser selectCell:filename inColumn:0])
  94.         [self browser:helpBrowser selectCell:GENERAL_HELP_FILE inColumn:0];
  95.     sprintf(helpFile,"%s/%s",helpDirectory,filename);
  96.     if ((stream = NXMapFile(helpFile,NX_READONLY)) == NULL)
  97.         stream = NXMapFile(noHelpFile,NX_READONLY);
  98.     if (stream != NULL) {
  99.         [helpPanel disableFlushWindow];
  100.         [[helpScrollView docView] readRichText:stream]; 
  101.         [[helpScrollView docView] scrollPoint:&origin];
  102.         [[helpPanel reenableFlushWindow] flushWindow];
  103.         NXCloseMemory(stream,NX_FREEBUFFER);
  104.     }
  105.     [helpPanel orderFront:self];
  106.     return self;
  107. }
  108.  
  109.  
  110. static BOOL isOk(const char *s)
  111. /* checks to make sure the filename is not NULL and to verify that it is
  112.  * not a "dot"--hidden file.
  113.  */
  114. {
  115.     return (!s[0] || s[0] == '.') ? NO : YES;
  116. }
  117.  
  118. static int caseInsensitiveCompare(void *arg1, void *arg2)
  119. /* Compares the two arguments without regard for case using strcasecmp().
  120. */
  121. {
  122.     char *string1, *string2;
  123.  
  124.     string1 = *((char **)arg1);
  125.     string2 = *((char **)arg2);
  126.     return strcasecmp(string1,string2);
  127. }
  128.  
  129. static char **fileList;
  130.  
  131. - (int)browser:sender fillMatrix:matrix inColumn:(int)column
  132. /* This delegate method goes out to the help directory and gets a list
  133.  * of all the files in that directory.  It creates a list of file names
  134.  * for the static variable fileList, and will load the filenames into the 
  135.  * browser on demand (lazy loading).
  136.  */
  137. {
  138.     long basep;
  139.     char *buf;
  140.     struct direct *dp;
  141.     char **list = NULL;
  142.     int cc, fd, fileCount = 0;
  143.     char dirbuf[8192];
  144.  
  145.     if ((fd = open(helpDirectory, O_RDONLY, 0644)) > 0) {
  146.         cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
  147.         while (cc) {
  148.             dp = (struct direct *)buf;
  149.             if (isOk(dp->d_name)) {
  150.                 list = addFile(dp->d_name, list, fileCount++, MyZone);
  151.             }
  152.             buf += dp->d_reclen;
  153.             if (buf >= dirbuf + cc) {
  154.                 cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
  155.             }
  156.         }
  157.         close(fd);
  158.         if (list) qsort(list,fileCount,sizeof(char *),caseInsensitiveCompare);
  159.     }
  160.     freeList(fileList);
  161.     fileList = list;
  162.     return fileCount;
  163. }
  164.  
  165. - browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
  166. /* This delegate method loads the cell for a given row.  The stringValue
  167.  * for that row comes from the fileList.
  168.  */
  169. {
  170.     if (fileList) {
  171.         id originalFont = [cell font];
  172.         id useFont = [Font newFont:LocalHelpFont() size:[originalFont pointSize]];
  173.         if (useFont) {
  174.             [cell setFont:useFont];
  175.             [originalFont free];
  176.         }
  177.         [cell setStringValueNoCopy:fileList[row]];
  178.         [cell setLeaf:YES];
  179.     }
  180.     return self;
  181. }
  182.  
  183.  
  184. - (BOOL)browser:sender selectCell:(const char *)title inColumn:(int)column
  185. /* This delegate method selects the cell with the given title.  If it finds
  186.  * a cell with that title, it verifies that it has a file entry in the 
  187.  * fileList, forces the loading of the cell, selects it (highlights) and
  188.  * scrolls the browser so the cell is visible.  It returns a boolean value
  189.  * which indicates whether the cell was found.
  190.  */
  191. {
  192.     int row;
  193.     id matrix;
  194.  
  195.     if (title) {
  196.         matrix = [sender matrixInColumn:column];
  197.         if (!fileList) return NO;
  198.         for (row = [matrix cellCount]-1; row >= 0; row--) {
  199.             if (fileList[row] && !strcmp(title, fileList[row])) {
  200.                 [sender getLoadedCellAtRow:row inColumn:column];
  201.                 [matrix selectCellAt:row :0];
  202.                 [matrix scrollCellToVisible:row :0];
  203.                 return YES;
  204.             }
  205.         }
  206.     }
  207.     return NO;
  208. }
  209.  
  210.  
  211. /* WINDOW DELEGATE METHODS */
  212.  
  213. - windowWillResize:sender toSize:(NXSize *)frameSize;
  214. /* This method constrains the Help Panel to a reasonable minimum size
  215.  * when the user resizes the panel.
  216.  */
  217. {
  218.     frameSize->width = MAX(frameSize->width,400.0);
  219.     frameSize->height = MAX(frameSize->height,350.0);
  220.     return self;
  221. }
  222.  
  223.  
  224. @end